﻿using System;
using System.Data;
using System.Data.Common;
using System.Reflection;

namespace Janus.Mes.Repositories.iBatis
{
    /// <summary>
    /// 为 SQL 提供批量处理操作。
    /// </summary>
    public class iSqlBatcher
    {
        private delegate void Action();
        public delegate R Func<R>();
        public delegate R Func<T, R>(T argument);
        private Type m_AdapterType;
        private MethodInfo m_AddToBatch;
        private MethodInfo m_ClearBatch;
        private MethodInfo m_InitializeBatching;
        private MethodInfo m_ExecuteBatch;
        private Func<IDbCommand, int> m_AddToBatchCall;
        private Action m_ClearBatchCall;
        private Action m_InitializeBatchingCall;
        private Func<int> m_ExecuteBatchCall;

        private IDbDataAdapter m_Adapter;
        private bool _Started;

        /// <summary>
        /// 构造一个新的 SqlBatcher。
        /// </summary>
        public iSqlBatcher(Type dataAdapterType)
        {
            if (null == dataAdapterType)
                throw new ArgumentNullException("dataAdapterType");
            if (!dataAdapterType.IsSubclassOf(typeof(DbDataAdapter)))
                throw new ArgumentException("类型必须继承自 System.Data.Common.DbDataAdapter 。", "dataAdapterType");
            m_AdapterType = dataAdapterType;
            m_AddToBatch = m_AdapterType.GetMethod("AddToBatch", BindingFlags.NonPublic | BindingFlags.Instance);
            m_ClearBatch = m_AdapterType.GetMethod("ClearBatch", BindingFlags.NonPublic | BindingFlags.Instance);
            m_InitializeBatching = m_AdapterType.GetMethod("InitializeBatching", BindingFlags.NonPublic | BindingFlags.Instance);
            m_ExecuteBatch = m_AdapterType.GetMethod("ExecuteBatch", BindingFlags.NonPublic | BindingFlags.Instance);

        }

        // 创建适配器实例
        private IDbDataAdapter CreateDataAdapter()
        {
            return (IDbDataAdapter)Activator.CreateInstance(m_AdapterType);
        }

        /// <summary>
        /// 获得批处理是否正在批处理状态。
        /// </summary>
        public bool Started
        {
            get { return _Started; }
        }

        /// <summary>
        /// 创建一个命令。
        /// </summary>
        /// <returns>创建的命令</returns>
        public IDbCommand CreateCommand()
        {
            if (!_Started) throw new InvalidOperationException();
            IDbCommand ret = m_Adapter.InsertCommand.Connection.CreateCommand();
            ret.Transaction = m_Adapter.InsertCommand.Transaction;
            return ret;
        }

        /// <summary>
        /// 开始批处理。
        /// </summary>
        /// <param name="connection">连接。</param>
        public void StartBatch(IDbConnection connection)
        {
            StartBatch(connection, null);
        }

        /// <summary>
        /// 开始批处理。
        /// </summary>
        /// <param name="connection">连接。</param>
        /// <param name="transaction">事务</param>
        public void StartBatch(IDbConnection connection, IDbTransaction transaction)
        {
            if (_Started) return;
            IDbCommand command = connection.CreateCommand();
            command.Transaction = transaction;
            m_Adapter = CreateDataAdapter();
            m_Adapter.InsertCommand = command;
            m_InitializeBatchingCall = (Action)Delegate.CreateDelegate(
                typeof(Action),
                m_Adapter,
                m_InitializeBatching);
            m_AddToBatchCall = (Func<IDbCommand, int>)Delegate.CreateDelegate(
                typeof(Func<IDbCommand, int>),
                m_Adapter,
                m_AddToBatch);
            m_ClearBatchCall = (Action)Delegate.CreateDelegate(
                typeof(Action),
                m_Adapter,
                m_ClearBatch);
            m_ExecuteBatchCall = (Func<int>)Delegate.CreateDelegate(
                typeof(Func<int>),
                m_Adapter,
                m_ExecuteBatch);

            m_InitializeBatchingCall.Invoke();
            _Started = true;
        }


        /// <summary>
        /// 添加批命令。
        /// </summary>
        /// <param name="command">命令</param>
        /// <returns>添加的命令数</returns>
        public int AddToBatch(IDbCommand command)
        {
            if (!_Started) throw new InvalidOperationException();
            return m_AddToBatchCall.Invoke(command);
        }

        /// <summary>
        /// 执行批处理。
        /// </summary>
        /// <returns>影响的数据行数。</returns>
        public int ExecuteBatch()
        {
            if (!_Started) throw new InvalidOperationException();
            int ret = m_ExecuteBatchCall.Invoke();
            return ret;
        }

        /// <summary>
        /// 结束批处理。
        /// </summary>
        public void EndBatch()
        {
            if (_Started)
            {
                ClearBatch();
                IDisposable dis = m_Adapter as IDisposable;
                if (dis != null)
                    dis.Dispose();
                m_Adapter = null;
                _Started = false;
            }
        }

        /// <summary>
        /// 清空保存的批命令。
        /// </summary>
        public void ClearBatch()
        {
            if (!_Started) throw new InvalidOperationException();
            m_ClearBatchCall.Invoke();
        }
    }
}
